/* 该程序中是在指定信号上阻塞的函数的对象实现，在调用simplesuspend前，
 * 程序调用initsuspend建立暂停 信号的处理函数。程序调用restore将信号重新设置为之前的状态
 */
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>

static int isinitialized = 0;
static struct sigaction oact;
static int signum = 0;
static volatile sig_atomic_t sigreceived = 0;

/* ATGSUSED */
static void catcher (int signo) {
    sigreceived = 1;
}

/* 为pause设置处理函数 */
int initsuspend (int signo) {
    struct sigaction act;
    if (isinitialized) return 0;    // 如果已经初始化，则退出
    
    act.sa_flags = 0;               // 没有特殊选项
    act.sa_handler = catcher;       // 设置act的处理程序
    
    // 捕获signo信号，该信号由形参传入
    if (sigfillset(&act.sa_mask) == -1 || sigaction(signo, &act, &oact) == -1) {
        return -1;
    }
    
    signum = signo;                 // 如果初始化成果，则将标志位置 1
    isinitialized = 1; 
    return 0;
}


/* 恢复信号之前状态的函数 */
int restore(void) {
    if (!isinitialized) return 0;   // 如果标志位为0，说明信号状态没有被改变
    // oact中存放的是sigaction处理之前的程序
    if (sigaction(signum, &oact, NULL) == -1) {
        return -1;
    }
    
    isinitialized = 0;
    return 0;
}

/* 显示在指定信号上阻塞的函数的对象实现 */
int simplesuspend(void) {
    sigset_t maskblocked, maskold, maskunblocked;
    if (!isinitialized) {
        errno = EINVAL;
        return -1;
    }

    if ((sigprocmask(SIG_SETMASK, NULL, &maskblocked) == -1) ||     // 保存处理信号之前的信号掩码到maskblocked
        (sigaddset(&maskblocked, signum) == -1) ||                  // 将signum添加到阻塞信号集中
        (sigprocmask(SIG_SETMASK, NULL, &maskunblocked) == -1) ||   // 将之前的信号集合存放到maskunblocked
        (sigdelset(&maskunblocked, signum) == -1) ||                // 将signum信号从非阻塞集合中移除
        (sigprocmask(SIG_SETMASK, &maskblocked, &maskold) == -1) )  // 将maskblock集合中的信号设置为阻塞
        return -1;

    while (sigreceived == 0) {
        sigsuspend(&maskunblocked);      // 将maskunblocked中的信号挂起，等待signum信号的到来
    }
    sigreceived = 0;
    return sigprocmask(SIG_SETMASK, &maskold, NULL);                // 恢复阻塞之前的信号
}

// 使用上面的程序来等待SIGUSR1信号
int main() {
    fprintf(stderr, "This is process %ld\n", (long)getpid());
    while (1) {
        // 将挂起的信号设置为SIGUSR1
        if (initsuspend(SIGUSR1)) {
            perror("Failed to setup handler for SIGUSR1");
            return 1;
        }

        fprintf(stderr, "Waiting for signal\n");
        if (simplesuspend()) {
            perror("Failed to suspend for signal");
            return 1;
        }

        fprintf(stderr, "Got signal\n");
        if (restore()) {
            perror("Failed to restore original handler");
            return 1;
        }
    }

    return 1;
}